#include "UARTDriverDBG.h"
#include "..\System\F2806x_Device.h"
#include <string.h>

extern UARTDriverDBG uartDBG;
extern "C" interrupt void UARTDriverDBGIntTX(void)
{
	uartDBG.WriteProcess();
	
	SciaRegs.SCIFFTX.bit.TXFFINTCLR=1;	// Clear SCI Interrupt flag
	PieCtrlRegs.PIEACK.all|=0x100;      // Issue PIE ACK
}

extern "C" interrupt void UARTDriverDBGIntRX(void)
{
	uartDBG.ReadProcess();
	
	SciaRegs.SCIFFRX.bit.RXFFOVRCLR=1;  // Clear Overflow flag
	SciaRegs.SCIFFRX.bit.RXFFINTCLR=1;	// Clear SCI Interrupt flag
	PieCtrlRegs.PIEACK.all|=0x100;      // Issue PIE ACK
}

// SCIA
bool UARTDriverDBG::Init(unsigned long baudRate)
{
	EALLOW;
	
	// 1. GPIO
	GpioCtrlRegs.GPAPUD.bit.GPIO28 = 0;    // Enable pull-up for GPIO28 (SCIRXDA)
	GpioCtrlRegs.GPAPUD.bit.GPIO29 = 0;	   // Enable pull-up for GPIO29 (SCITXDA)
	GpioCtrlRegs.GPAQSEL2.bit.GPIO28 = 3;  // Asynch input GPIO28 (SCIRXDA)
	GpioCtrlRegs.GPAMUX2.bit.GPIO28 = 1;   // Configure GPIO28 for SCIRXDA operation
	GpioCtrlRegs.GPAMUX2.bit.GPIO29 = 1;   // Configure GPIO29 for SCITXDA operation
	
    // 2. BAUD AND CONFIG
    SciaRegs.SCICCR.all =0x0007;   // 1 stop bit,  No loopback, No parity,8 char bits, async mode, idle-line protocol
	SciaRegs.SCICTL1.all =0x0003;  // enable TX, RX, internal SCICLK, Disable RX ERR, SLEEP, TXWAKE
	SciaRegs.SCICTL2.all =0x0000; // clear all
	SciaRegs.SCIHBAUD    =0x0000; 
	long rate = 20E6L /(baudRate*8)-1; // @LSPCLK = 20.0MHz (80Mhz/4)
	SciaRegs.SCILBAUD = rate; // set rate 
	
	// 3. FIFO (NOTE: TX INT Disbaled in Sysinit.c)
	SciaRegs.SCIFFTX.bit.TXFIFOXRESET = 0; // hold in reset
	SciaRegs.SCIFFTX.bit.SCIRST = 1; // enable
	SciaRegs.SCIFFTX.bit.SCIFFENA = 1; // enable Fifo
	SciaRegs.SCIFFTX.bit.TXFFINTCLR = 1; // ack int
	SciaRegs.SCIFFTX.bit.TXFFIENA = 0; // disable fifo match int (will be enabled when needed)
	SciaRegs.SCIFFTX.bit.TXFFIL = 0; // level = 0 (int when empty)
    SciaRegs.SCIFFCT.all=0x00;
   
	// RX
	SciaRegs.SCIFFRX.bit.RXFIFORESET = 0; // hold in reset
	SciaRegs.SCIFFRX.bit.RXFFOVRCLR=1;   // Clear Overflow flag
	SciaRegs.SCIFFRX.bit.RXFFINTCLR=1;	// Clear SCI Interrupt flag
	SciaRegs.SCIFFRX.bit.RXFFIENA = 1;	// enable rx fifo on match
	SciaRegs.SCIFFRX.bit.RXFFIL = 4; // level = 4 (int only when fifo is full, note: this CPU has only 4-level FIFO size!!!)
   
	SciaRegs.SCICTL1.all =0x0023;  // Relinquish SCI from Reset   
 	SciaRegs.SCIFFRX.bit.RXFIFORESET = 1; // renable fifo
 	SciaRegs.SCIFFTX.bit.TXFIFOXRESET=1; // renable fifo
	   
 	EDIS;
 	
 	m_Buffer.clear(); // clear buffer
 	m_BufferRX.clear();
 	
 	// enable INTs
 	EALLOW;
 	PieVectTable.SCITXINTA = &UARTDriverDBGIntTX;
	PieVectTable.SCIRXINTA = &UARTDriverDBGIntRX;
 	EDIS;
 	
 	PieCtrlRegs.PIECTRL.bit.ENPIE = 1;   // Enable the PIE block
	PieCtrlRegs.PIEIER9.bit.INTx1=1;     // PIE Group 9, INT1, RX SCI-A
	PieCtrlRegs.PIEIER9.bit.INTx2=1;     // PIE Group 9, INT2, TX SCI-A
	IER |= M_INT9; // enable group 9 int
 	
	return true;
}

// WRITE
void UARTDriverDBG::SendChar(char ch)
{
	while (SciaRegs.SCIFFTX.bit.TXFFST != 0) {}
    SciaRegs.SCITXBUF=ch;
}

void UARTDriverDBG::SendData(char* buffer, int length)
{
	for(int i=0; i!= length; i++)
	{
		SendChar(*buffer);
		buffer++;
	}
}

void UARTDriverDBG::SendData16(char* buffer, int length)
{
	for(int i=0; i!= length; i++)
	{
		char ch = *buffer;
		char ch1 = ch & 0x00FF; // low byte
		char ch2 = (ch >> 8); // high byte
		SendChar(ch1);
		SendChar(ch2);
		buffer++;
	}
}

void UARTDriverDBG::SendData(char* buffer)
{
	SendData(buffer, strlen(buffer));
} 

bool UARTDriverDBG::QueueData(char* data)
{
	bool ok = true;
	DINT;
	if( m_Buffer.size() < 100 ) // limit maximum buffer size
	{
		while(*data!=NULL) m_Buffer.push_back(*data++);		
	}
	else ok = false;
	SciaRegs.SCIFFTX.bit.TXFFIENA = 1; // enable fifo match int
	WriteProcess();
	EINT;
	
	return ok;
}

bool UARTDriverDBG::QueueData(char* data, int size)
{
	bool ok = true;
	DINT;
	if( m_Buffer.size() < 100 ) // limit maximum buffer size
	{
		for(int i=0; i!= size; i++ )
		{
			m_Buffer.push_back(*data++);
		}		
	}
	else ok = false;
	SciaRegs.SCIFFTX.bit.TXFFIENA = 1; // enble fifo match int
	WriteProcess();
	EINT;
	
	return ok;
}

void UARTDriverDBG::WriteProcess()
{
	while( m_Buffer.size() > 0 && SciaRegs.SCIFFTX.bit.TXFFST < 4) // have data to send and fifo is available
	{
		// put to fifo
		char ch = m_Buffer.front();
		SciaRegs.SCITXBUF=ch; 
		m_Buffer.pop_front(); // remove
	}
	if( SciaRegs.SCIFFTX.bit.TXFFST == 0) 
	{
		// no more data to send, disable INT
		SciaRegs.SCIFFTX.bit.TXFFIENA = 0; // disable fifo match int
	}
}

// READ
bool UARTDriverDBG::ReadChar(char& ch)
{
	if( SciaRegs.SCIFFRX.bit.RXFFST == 0 ) return false; // no data in FIFO
	ch = SciaRegs.SCIRXBUF.all;
	
	return true;
}

Uint32 UARTDriverDBG::ReadData(char* buffer)
{
	int i = 0;
	bool haveMore = ReadChar(buffer[i]);

	while(haveMore)
	{
		i++;
		haveMore = ReadChar(buffer[i]);
	}
	
	return i;
}

Uint32 UARTDriverDBG::GetData(char* buffer)
{
	int size = 0;
	
	DINT;
	ReadProcess(); // flush data
	while(m_BufferRX.size() > 0 )
	{
		char ch = m_BufferRX.front();
		*buffer = ch;
		buffer++;
		size++;
		m_BufferRX.pop_front(); // remove
	}
	EINT;
	
	return size;
}

void UARTDriverDBG::ReadProcess()
{
	while( SciaRegs.SCIFFRX.bit.RXFFST > 0 ) // have new data
	{
		char ch = SciaRegs.SCIRXBUF.all;	 // Read data
		if( m_BufferRX.size() < 100 ) m_BufferRX.push_back(ch);
	}
}
